package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.MyAutowired;
import com.lagou.edu.annotation.MyService;
import com.lagou.edu.annotation.MyTransactional;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author 应癫
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactoryAnnotation {

    /**
     * 任务一：读取指定包下的实例对象
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static HashMap<String, Object> map = new HashMap<>();  // 存储对象


    static {
        //  加载 指定包下存入 map 集合
        // 任务一：获取指定路径下类的集合并放入 map 当中,根据类上的注解，字段再进行装配
        Reflections reflections = new Reflections("com.lagou.edu");
        // 拿到所有类，存入map 当中
        Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(MyService.class);
        for (Class<?> e : classSet) {

            //  拿到service 中所有的类，放入map集合中
            try {
                Object object = e.getDeclaredConstructor().newInstance();
                MyService service = e.getAnnotation(MyService.class);
                if (StringUtils.isEmpty(service.value())) {
                    //由于getName获取的是全限定类名，所以要分割去掉前面包名部分
                    String[] names = e.getName().split("\\.");
                    map.put(names[names.length - 1], object);

                } else {
                    map.put(service.value(), object);
                }


            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        DefiledSet();

    }

    private static void DefiledSet() {
        // 遍历map集合，装配属性
        //维护对象之间依赖关系
        for (Map.Entry<String, Object> entrySet : map.entrySet()) {
            Object obj = entrySet.getValue();
            Class clazz = obj.getClass();
            //获取每个类的所有属性
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                if (field.isAnnotationPresent(MyAutowired.class) &&
                        field.getAnnotation(MyAutowired.class).value()) {
                    String[] names = field.getType().getName().split("\\.");
                    String name = names[names.length - 1];
                    Method[] methods = clazz.getMethods();

                    for (int j = 0; j < methods.length; j++) {
                        Method method = methods[j];
                        if (method.getName().equalsIgnoreCase("set" + name)) {  // 该方法就是 setAccountDao(AccountDao accountDao)
                            try {
                                method.invoke(obj, map.get(name));
                            } catch (IllegalAccessException illegalAccessException) {
                                illegalAccessException.printStackTrace();
                            } catch (InvocationTargetException invocationTargetException) {
                                invocationTargetException.printStackTrace();
                            }
                        }
                    }


                }
            }
            // 将需要事务管理的对象，包装成代理，重新存入
            //判断当前类是否有Transactional注解，若有则使用代理对象
            if(clazz.isAnnotationPresent(MyTransactional.class)){
                //获取代理工厂
                ProxyFactory proxyFactory = (ProxyFactory) BeanFactoryAnnotation.getBean("proxyFactory");
                Class[] face = clazz.getInterfaces();//获取类c实现的所有接口
                //判断对象是否实现接口
                if(face!=null&&face.length>0){
                    //实现使用JDK
                    obj = proxyFactory.getJdkProxy(obj);
                }else{
                    //没实现使用CGLIB
                    obj = proxyFactory.getCglibProxy(obj);
                }
            }
            // 把处理之后的object重新放到map中
            map.put(entrySet.getKey(),obj);
        }
    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }

}
